home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Tool Chest / Development Kits / MPW etc. / Debuggers / SADE / SADE 1.4a3 / SadeStartup < prev    next >
Encoding:
Text File  |  1992-07-10  |  28.1 KB  |  901 lines  |  [TEXT/sade]

  1. ##########################################################################################
  2. #    Symbolic Application Debugging Environment    1.4
  3. #
  4. #    copyright Apple Computer, Inc. 1987-1992
  5. #    All rights reserved.
  6. #
  7. ##########################################################################################
  8. #
  9. # SADEStartup -- default OnEntry mechanism and support for source level debugging.
  10. #
  11.  
  12. #
  13. # The following variables are used by the OnEntry and source & variable display mechanism.
  14. #
  15. define __SourceDbg__     := 1             # controls source vs. low-level debugging
  16. define __MaxWatchVars__  := 10           # maximum number of watched variables
  17. define __NumWatchVars__  := 0            # current number of watch variables
  18. define __WatchVar__[__MaxWatchVars__]   # names of variables to watch
  19. define __MaxBreakifs__   := 10           # maximum number of conditional breaks
  20. define __BreakifAddr__[__MaxBreakifs__] # conditional break addresses
  21. define __BreakifCond__[__MaxBreakifs__] # conditional break conditions
  22. define __i__
  23. for __i__ := 1 to __MaxBreakifs__ do
  24.     __BreakifAddr__[__i__] := 0
  25. end
  26. undefine __i__
  27.  
  28. func __GetDirectoryFromFullPath__(FullPathName)
  29.     define DirName := FullPathName
  30.     define __i__
  31.     for __i__ := length(DirName) downto 1 do
  32.         if copy(DirName,__i__,1) = ':' then
  33.             DirName := copy(DirName,1,__i__)
  34.             return DirName
  35.         end
  36.     end
  37.     return FullPathName
  38. end
  39.  
  40. func __GetFileFromFullPath__(FullPathName)
  41.     define FileName := FullPathName
  42.     define __i__
  43.     for __i__ := length(FileName) downto 1 do
  44.         if copy(FileName,__i__,1) = ':' then
  45.             FileName := copy(FileName, __i__+1, length(FileName))
  46.             return FileName
  47.         end
  48.     end
  49.     return FullPathName
  50. end
  51.  
  52. define SADEDir := __GetDirectoryFromFullPath__(WorksheetWindow)
  53.  
  54. # The "temporary" windows created by Sade are real files.
  55. # These are the register window, the value window, the stack window etc.
  56. # You can select the directory in which they accumulate. If you have a ramdisk,
  57. # override the next line in your SadeUserStartup.
  58. define __ScratchDir__ := concat(SADEDir, 'SADE Scratch:')
  59. macro __gValueWindow__ "concat(__ScratchDir__, 'Value')"
  60. macro __gRegisterWindow__ "concat(__ScratchDir__, 'Registers')"
  61. macro __gStackWindow__ "concat(__ScratchDir__, 'Stack Window')"
  62.  
  63. # This sets the size of new windows [top, left, bottom, right]
  64. WindowSize New 0, 0, 200, 400
  65.  
  66. # General error-handling proc.
  67. proc __Fail__(__ErrorString__)
  68.     alert __ErrorString__
  69.     redirect pop
  70.     abort
  71. end
  72.  
  73. # This macro is used by scripts below to check if there is a valid target.
  74. macro CheckNullTarget        'if processId = 0 then;alert "No process targeted.";abort;end'
  75.  
  76. # This macro is used to check if the target is running.
  77. macro CheckRunningTarget    'if TargetRunning then;alert "Target is running.";abort;end'
  78. macro CheckNullOrRunningTarget    'CheckNullTarget;CheckRunningTarget'
  79.  
  80. # This macro is used to see if we are at a "LINK A6, #$xxxx" instruction
  81. # (local variables are not valid until after the instruction has executed).
  82. macro PCIsAtLinkA6    '^ΔWord(ΔPC)^ = $4E56'    # LINK opword = $4E56
  83.  
  84. # If we haven't executed the LINK instruction, print a warning.
  85. proc CheckValidLocalVars
  86.     CheckRunningTarget
  87.     if PCIsAtLinkA6 then
  88.         printf "Note: Parameters and local variables\naren't valid yet at this statement.\n"
  89.     end
  90. end
  91.  
  92. #
  93. # You may change the default values below to change how source level displays work.
  94. #
  95. define SourceInFront := 1    # controls whether source will be brought up as frontmost window
  96.  
  97. # Set this if you want an alert on hitting a breakpoint.
  98. define Breakalert := 0    # controls breakpoint alert
  99.  
  100. # Set __WantStackWindow__ to 1 if you want a live Stack window which updates every
  101. # time you step.  Since this slows things down, you may prefer to leave it 0 and just
  102. # ask for a snapshot of the stack when you need to.
  103. define __WantStackWindow__ := 0         # controls stack display
  104.  
  105. # Stack display -- the DoStack and DisplayStack procs
  106. proc DoStack
  107.     redirect __gStackWindow__
  108.     if PCIsAtLinkA6 then
  109.         printf "Stack isn't valid yet at this statement.\n"
  110.     else
  111.         stack
  112.     end
  113.     redirect pop
  114.     open __gStackWindow__
  115. end
  116.  
  117. proc DisplayStack
  118.     CheckNullTarget
  119.     if TargetRunning then
  120.         alert "The target is running.  You must halt it to see its stack."
  121.         abort
  122.     end
  123.     DoStack
  124. end
  125.  
  126. proc ToggleWantStackWindow
  127.     if __WantStackWindow__ = 0 then
  128.         __WantStackWindow__ := 1
  129.         open __gStackWindow__
  130.         addmenu 'Variables' '!Live Stack Window' 'ToggleWantStackWindow'     # '' is control-r (a checkmark)
  131.         DisplayStack
  132.     else
  133.         __WantStackWindow__ := 0
  134.         save __gStackWindow__
  135.         close __gStackWindow__
  136.         addmenu 'Variables' 'Live Stack Window' 'ToggleWantStackWindow'
  137.     end
  138. end
  139.  
  140. # Set __WantRegisterWindow__ to 1 if you want a live Registers window which updates every
  141. # time you step.  Since this slows things down, you may prefer to leave it 0 and just
  142. # ask for a snapshot of the registers when you need to.
  143. define __WantRegisterWindow__ := 0         # controls register display
  144.  
  145. #
  146. # Register display -- the Registers and DisplayRegs procs
  147. #
  148. proc Registers        # This definition must precede the proc DisplayRegs
  149.     redirect __gRegisterWindow__
  150.     printf ("D0: $%.8X\nD1: $%.8X\nD2: $%.8X\nD3: $%.8X\nD4: $%.8X\nD5: $%.8X\nD6: $%.8X\nD7: $%.8X\n\n",ΔD0,ΔD1,ΔD2,ΔD3,ΔD4,ΔD5,ΔD6,ΔD7)
  151.     printf ("A0: $%.8X\nA1: $%.8X\nA2: $%.8X\nA3: $%.8X\nA4: $%.8X\nA5: $%.8X\nA6: $%.8X\nA7: $%.8X\n\n",ΔA0,ΔA1,ΔA2,ΔA3,ΔA4,ΔA5,ΔA6,ΔA7)
  152.     printf ("PC: $%.8X\n\n",ΔPC)
  153.     printf ("\tXNZVC\n")
  154.     printf ("CCR\t%.5b\n",(ΔCCR & $1F))
  155.     redirect pop
  156. end
  157.  
  158. proc DisplayRegs # This definition must precede the proc ToggleWantRegisterWindow
  159.     CheckNullOrRunningTarget
  160.     if TargetRunning then
  161.         alert "The target is running.  You must halt it to see its registers."
  162.         abort
  163.     end
  164.     Registers
  165.     open __gRegisterWindow__
  166. #    SizeWindow To 160,295 __gRegisterWindow__
  167. end
  168.  
  169. proc ToggleWantRegisterWindow
  170.     if __WantRegisterWindow__ = 0 then
  171.         __WantRegisterWindow__ := 1
  172.         addmenu    'Variables' '!Live Register Window' 'ToggleWantRegisterWindow'     # '' is control-r (a checkmark)
  173.         DisplayRegs
  174.         open __gRegisterWindow__
  175.     else
  176.         __WantRegisterWindow__ := 0
  177.         save __gRegisterWindow__
  178.         close __gRegisterWindow__
  179.         addmenu    'Variables' 'Live Register Window' 'ToggleWantRegisterWindow'
  180.     end
  181. end
  182.  
  183. #
  184. # You can set the Safety variable to 1 if you want SADE to be more careful
  185. # when stepping and breaking.  The default setting slightly increases the
  186. # possibility of SADE crashing because of a memory stomper in user code,
  187. # but makes stepping and breaking ten times faster.
  188. #
  189. Safety := 0
  190.  
  191. #
  192. # By default, BreakifNoSource is false.  This allows SADE to step
  193. # through routines like LMODT and UDIVT.  It also lets SADE step
  194. # through Object Pascal and MacApp method dispatch code.  However,
  195. # if you have enabled symbolics for only a small portion of your
  196. # code and do a step into, it will appear that SADE has hung when
  197. # it is really single stepping through zillions of instructions.
  198. # The default setting of 0 supports MacApp and avoids mystery
  199. # breaks in LMODT.  See the "SADE New User WorkSheet" for details.
  200. BreakifNoSource := 0
  201.  
  202. proc ToggleBreakifNoSource
  203.     if BreakifNoSource = 0 then
  204.         BreakifNoSource := 1
  205.         addmenu 'SourceCmds' '!Break if No Source' 'ToggleBreakifNoSource'     # '' is control-r (a checkmark)
  206.     else
  207.         BreakifNoSource := 0
  208.         addmenu 'SourceCmds' 'Break if No Source' 'ToggleBreakifNoSource'
  209.     end
  210. end
  211.  
  212. #
  213. # By default, __StopBeforeStatic__ is 0.  This makes SADE step to
  214. # main.(0) when an application is launched.  If you set it to 1, SADE
  215. # will give you control before any code in the app is run.  You can then
  216. # place breakpoints at your static constructors before you proceed.
  217. #
  218. define __StopBeforeStatic__ := 0
  219.  
  220. proc ToggleStopBeforeStatic
  221.     if __StopBeforeStatic__ = 0 then
  222.         __StopBeforeStatic__ := 1
  223.         addmenu 'File' '!Stop Before Constructor' 'ToggleStopBeforeStatic'
  224.     else
  225.         __StopBeforeStatic__ := 0
  226.         addmenu 'File' 'Stop Before Constructor' 'ToggleStopBeforeStatic'     # '' is control-r (a checkmark)
  227.     end
  228. end
  229.  
  230. proc ToggleSourceDbg
  231.     if __SourceDbg__ = 0 then
  232.         __SourceDbg__ := 1
  233.         deletemenu 'SourceCmds' '!Asm [vs. Source] Debugging'     # '' is control-r (a checkmark)
  234.         addmenu 'SourceCmds' '!Source [vs. Asm] Debugging' 'ToggleSourceDbg'     # '' is control-r (a checkmark)
  235.     else
  236.         __SourceDbg__ := 0
  237.         deletemenu 'SourceCmds' '!Source [vs. Asm] Debugging'     # '' is control-r (a checkmark)
  238.         addmenu 'SourceCmds' '!Asm [vs. Source] Debugging' 'ToggleSourceDbg'     # '' is control-r (a checkmark)
  239.     end
  240. end
  241.  
  242. # Return true if the 1st character of __theStr__ is in [A-Z,a-z,_]
  243. func IsAlpha(__theStr__)
  244.     define __theChar__ := copy(__theStr__, 1, 1)
  245.     if (__theChar__ >= 'a') and (__theChar__ <= 'z') then
  246.         return 1
  247.     end
  248.     if (__theChar__ >= 'A') and (__theChar__ <= 'Z') then
  249.         return 1
  250.     end
  251.     if (__theChar__ = '_') then
  252.         return 1
  253.     end
  254.     return 0
  255. end
  256.  
  257. # Add a backquote to the selected name to evaluate it as a program variable.
  258. func QualifiedVariableName(__VarName__)
  259.     if copy(__VarName__, 1, 1) = '`' then
  260.         return __VarName__
  261.     end
  262.     if IsAlpha(__VarName__)
  263.         return concat('`', __VarName__)
  264.     end
  265.     return __VarName__
  266. end
  267.  
  268. func CheckedEval(__Expression__, __ErrorString__)
  269.     define __EvaledExpr__
  270.     __EvaledExpr__ := eval(__Expression__,'???')
  271.     if typeof(__EvaledExpr__) = 'PString' then
  272.         if __EvaledExpr__ = '???' THEN
  273.             __Fail__(concat(__ErrorString__, __Expression__))
  274.         elseif copy(__EvaledExpr__, 1, 21) = '### eval syntax error' then
  275.             __Fail__(concat('Expression syntax error: ', __Expression__))
  276.         end
  277.     end
  278.     return __EvaledExpr__
  279. end
  280.  
  281. # Print a variable's name and value, with linebreaks as necessary.
  282. proc PrettyPrintValue(__TheVarName__)
  283. #    __TheVarName__ := QualifiedVariableName(__TheVarName__)
  284.     define __EvaledVar__ := CheckedEval(__TheVarName__, 'Undefined/Out of scope: ')
  285.     if sizeof(__EvaledVar__) > 4 then
  286.         printf "%s =\n%t\n", __TheVarName__, __EvaledVar__
  287.     else
  288.         printf "%s = %t\n", __TheVarName__, __EvaledVar__
  289.     end
  290. end
  291.  
  292. # Print a variable's name and its value in hex, with linebreaks as necessary.
  293. proc PrettyPrintValueInHex(__TheVarName__)
  294. #    __TheVarName__ := QualifiedVariableName(__TheVarName__)
  295.     define __EvaledVar__ := CheckedEval(__TheVarName__, 'Undefined/Out of scope: ')
  296.     if typeof(__EvaledVar__) = 'PString' then
  297.         printf "Printing strings as hex values does not work well.\n"
  298.     end
  299.     if sizeof(__EvaledVar__) > 4 then
  300.         printf "%s = Can not print non-integral objects as hex values.\n",__TheVarName__
  301.         return
  302.     else
  303.         printf "%s = $%X\n", __TheVarName__, __EvaledVar__
  304.     end
  305. end
  306.  
  307. proc PrettyPrintValueNoalert(__TheVarName__)
  308.     __TheVarName__ := QualifiedVariableName(__TheVarName__)
  309.     define __EvaledVar__ := eval(__TheVarName__, '???')
  310.     if typeof(__EvaledVar__) = 'PString' THEN
  311.         if __EvaledVar__ = '???' THEN
  312.             Printf "%s = Undefined/Out of scope\n", __TheVarName__
  313.             return
  314.         elseif copy(__EvaledVar__, 1, 21) = '### eval syntax error' then
  315.             Printf "%s = Expression syntax error\n", __TheVarName__
  316.             return
  317.         end
  318.     end
  319.     if sizeof(__EvaledVar__) > 4 then
  320.         printf "%s =\n%t\n", __TheVarName__, __EvaledVar__
  321.     else
  322.         printf "%s = %t\n", __TheVarName__, __EvaledVar__
  323.     end
  324. end
  325.  
  326. # Display the watch variables.
  327. proc DisplayWatchVars
  328.     define __i__
  329.     redirect concat(__ScratchDir__, "Variable Watch")
  330.     CheckValidLocalVars
  331.     for __i__ := 1 to __NumWatchVars__ do
  332.         PrettyPrintValueNoalert(__WatchVar__[__i__])
  333.     end
  334.     redirect pop
  335.     open behind concat(__ScratchDir__, "Variable Watch")
  336. end
  337.  
  338. #••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  339. #
  340. # Entry handling -- the StandardEntry proc
  341. #
  342. macro kSEProcessLoaded        '65'
  343. macro kSETrace                '51'
  344. macro kSEAddressBreak        '58'
  345. macro kSESADEKeyInterrupt    '55'
  346. macro kSEProcessHalted        '8194'
  347. macro kSEMemoryProtectFault    '66'
  348.  
  349. func GetErrorString()
  350.     define __errCause__ := ''
  351.     if Exception = kSETrace then
  352.         __errCause__ := "Instruction trace"
  353.     elseif Exception = kSEAddressBreak then
  354.         __errCause__ := "Address Break encountered"
  355.     elseif Exception = 50 then
  356.         __errCause__ := "Trap Break encountered"
  357.     elseif (Exception = kSESADEKeyInterrupt) | (Exception = 13) then 
  358.         __errCause__ := "Program interrupted"
  359.     elseif (Exception = kSEProcessHalted) then 
  360.         __errCause__ := "Process Halted"
  361.     elseif Exception = 1 then
  362.         __errCause__ := "Bus Error"
  363.     elseif Exception = 2 then
  364.         __errCause__ := "Address Error"
  365.     elseif Exception = 3 then
  366.         __errCause__ := "Illegal instruction encountered"
  367.     elseif Exception = 4 then
  368.         __errCause__ := "Divide by zero encountered"
  369.     elseif Exception = 5 then
  370.         __errCause__ := "CHK exception (array index out of range) encountered"
  371.     elseif Exception = 6 then
  372.         __errCause__ := "TRAPV or TRAPcc instruction encountered"
  373.     elseif Exception = 7 then
  374.         __errCause__ := "Privilege Violation"
  375.     elseif Exception = 63 then
  376.         __errCause__ := "Internal non-fatal error!  You may be able to proceed..."
  377.     elseif Exception = 64 then
  378.         __errCause__ := "Internal fatal error!  Please kill the target process!"
  379.     elseif Exception = kSEProcessLoaded then
  380.         __errCause__ := "Initial program break encountered"
  381.     elseif Exception = kSEMemoryProtectFault then
  382.         __errCause__ := "Write to protected memory detected"
  383.     elseif Exception = -490 then
  384.         __errCause__ := "User Break encountered"
  385.     elseif Exception = -491 then
  386.         __errCause__ := concat ("∂"", ^PString(ΔSP^)^, "∂"")
  387.         ΔSP := ΔSP+4;
  388.     elseif Exception = -492 then
  389.         __errCause__ := concat ("Execute message not implemented ∂"", ^PString(ΔSP^)^, "∂"")    # currently no way to execute this from SADE!
  390.         ΔSP := ΔSP+4;
  391.     elseif Exception = -490 then
  392.         __errCause__ := "User Break encountered"
  393.     else
  394.         __errCause__ := concat('Error number ', Exception)
  395.     end
  396.     return __errCause__
  397. end
  398.  
  399. proc __BreakBehavior__(__errCause__)
  400.     alert concat(__errCause__, ' at ', where(ΔPC))
  401. #    Beep
  402. end
  403.  
  404. proc __UserEntryBehavior__
  405. end
  406.  
  407. proc StandardEntry
  408.     __UserEntryBehavior__
  409.  
  410.     # if we are at the startup code for a C program, move ahead to main.(0)
  411.     if Exception = kSEProcessLoaded then
  412.         if __StopBeforeStatic__ = 0 then
  413.             if eval('main.(0)', '????') <> '????' then
  414.                 go til main.(0)
  415.                 stop
  416.             end
  417.         end
  418.     end
  419.  
  420.     define __errCause__
  421.     if __SourceDbg__ then
  422.         if addrToSource(ΔPC, SourceInFront) and (Exception > 0) then
  423.             if Exception <> kSETrace then
  424.                 __errCause__ := GetErrorString()
  425.                 if Breakalert then 
  426.                     __BreakBehavior__(__errCause__)
  427.                 elseif (Exception <> kSEprocessLoaded) and (Exception <> kSEAddressBreak) and (Exception <> kSESADEKeyInterrupt) then
  428.                     alert concat(__errCause__, ' at ', where(ΔPC))
  429.                 end
  430.             end
  431.         else
  432.             open WorksheetWindow
  433.             __errCause__ := GetErrorString()
  434.             printf "%s at ", __errCause__
  435.             disasm ΔPC 1
  436.         end
  437.     else        # Assembly mode
  438.         open WorksheetWindow
  439.         if Exception <> kSETrace then
  440.             __errCause__ := GetErrorString()
  441.             printf "%s at ", __errCause__
  442.         end
  443.         disasm ΔPC 1
  444.     end
  445.     
  446.     if __NumWatchVars__ > 0 then
  447.         DisplayWatchVars
  448.     end
  449.  
  450.     if __WantStackWindow__ then
  451.         DoStack
  452.     end
  453.  
  454.     if __WantRegisterWindow__ then
  455.         Registers
  456.     end
  457. end
  458.  
  459. OnEntry StandardEntry
  460.  
  461.  
  462. #
  463. # Macsbug equivalent command names for SADE
  464. # if you want these, remove the leading comments.
  465. # NOTE that these macros will be found before any program variables
  466. # of the same name!
  467. #
  468. # macro    g         "go"
  469. # macro    il        "disasm"
  470. # macro    ip        "disasm ΔPC-20 40"
  471. # macro    br        "break"
  472. # macro    ht        "heap totals"
  473. # macro    hd        "heap display"
  474. # macro    atba    "break all traps from applzone..applzone^"
  475. # macro    mc        "macro"
  476. # macro    id        "disasm"
  477. # macro    sc        "stack"
  478. # macro td        "registers"
  479.  
  480. #
  481. # Source Breakpoints
  482. #
  483. proc SetSourceBreak
  484.     CheckNullTarget
  485.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  486.     if typeof(__sourceBreak__) = 'PString' then
  487.         alert concat('Cannot determine break address: ', __sourceBreak__)
  488.     else
  489.         break __sourceBreak__
  490.         if not addrToSource(__sourceBreak__, 1) then    # verify statement selection
  491.             alert 'Able to set but not display breakpoint; SourcePath may not be set'
  492.         end
  493.     end
  494. end
  495.  
  496. proc ProcessBreakIf        # used by SetSourceBreakIf below
  497.     define __i__
  498.     define __addr__
  499.     for __i__ := 1 to __MaxBreakifs__ do
  500.         __addr__ := __BreakifAddr__[__i__]
  501.         if __addr__ = ΔPC then
  502.             if eval(__BreakifCond__[__i__]) then
  503.                 stop
  504.             end
  505.         end
  506.     end
  507. end
  508.  
  509. proc SetSourceBreakIf
  510.     CheckNullTarget
  511.     define __i__, __j__, __condition__, __EvaledCondition__
  512.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  513.     if typeof(__sourceBreak__) = 'PString' then
  514.         alert concat('Cannot determine break address: ', __sourceBreak__)
  515.         abort
  516.     end
  517.     if (__condition__ := request('Condition to break on?')) = '_CANCEL_' then
  518.         abort
  519.     end
  520.     if __condition__ = '' then
  521.         alert 'No condition was specified; break not set'
  522.         abort
  523.     end
  524.     # check for valid condition
  525.     __EvaledCondition__ := eval(__condition__, '???')
  526.     if typeof(__EvaledCondition__) = 'PString' then
  527.         if __EvaledCondition__ = '???' then
  528.             if not confirm('Variable not defined in current scope.  Still set conditional break?') then
  529.                 abort
  530.             end
  531.         elseif copy(__EvaledCondition__, 1, 21) = '### eval syntax error' then
  532.             alert concat('Cannot set conditional break.  Expression syntax error: ', __condition__)
  533.             abort
  534.         end
  535.     end
  536.     # try to add to conditional break table
  537.     for __i__ := 1 to __MaxBreakifs__ + 1 do
  538.         if __i__ = (__MaxBreakifs__ + 1) then
  539.             if not confirm('Conditional break table full; remove the oldest conditional break?') then
  540.                 abort
  541.             end
  542.             unbreak __BreakifAddr__[1]                # remove the first installed
  543.             for __j__ := 2 to __MaxBreakifs__ do    # shift the others over
  544.                 __BreakifAddr__[__j__ - 1] := __BreakifAddr__[__j__]
  545.                 __BreakifCond__[__j__ - 1] := __BreakifCond__[__j__]
  546.             end                                        # remember the new one
  547.             __BreakifAddr__[__MaxBreakifs__] := __sourceBreak__
  548.             __BreakifCond__[__MaxBreakifs__] := __condition__
  549.             leave
  550.         elseif (__BreakifAddr__[__i__] = 0) | (__sourceBreak__ = __BreakifAddr__[__i__]) then
  551.             __BreakifAddr__[__i__] := __sourceBreak__
  552.             __BreakifCond__[__i__] := __condition__
  553.             leave
  554.         end
  555.     end
  556.     break __sourceBreak__ processBreakIf
  557.     if not addrToSource(__sourceBreak__, 1) then    # verify statement selection
  558.         alert 'Able to set but not display breakpoint; SourcePath may not be set'
  559.     end
  560. end
  561.  
  562. proc __ClearBreakTable__
  563.     define __i__
  564.     for __i__ := 1 to __MaxBreakifs__ do
  565.         __BreakifAddr__[__i__] := 0
  566.     end
  567. end
  568.  
  569. proc __UnbreakAll__
  570.     CheckNullTarget
  571.     Unbreak All
  572.     __ClearBreakTable__
  573. end
  574.  
  575. proc UnSetSourceBreak
  576.     CheckNullTarget
  577.     define __i__
  578.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  579.     if typeof(__sourceBreak__) = 'PString' then
  580.         alert concat('Cannot determine break address: ', __sourceBreak__)
  581.     else
  582.         unbreak __sourceBreak__
  583.         for __i__ := 1 to __MaxBreakifs__ do                # remove from Breakif table if present
  584.             if __sourceBreak__ = __BreakifAddr__[__i__] then
  585.                 __BreakifAddr__[__i__] := 0
  586.                 leave
  587.             end
  588.         end
  589.         if addrToSource(__sourceBreak__, 1) then; end    # verify statement selection
  590.     end
  591. end
  592.  
  593. proc StepMenu
  594.     CheckNullOrRunningTarget
  595.     if __SourceDbg__ = 0 then
  596.         step asm
  597.     else
  598.         step
  599.     end
  600. end
  601.  
  602. proc StepIntoMenu
  603.     CheckNullOrRunningTarget
  604.     if __SourceDbg__ = 0 then
  605.         step asm into
  606.     else
  607.         step into
  608.     end
  609. end
  610.  
  611. proc StepOut
  612.     CheckNullOrRunningTarget
  613.     if PCIsAtLinkA6    then    # if we are looking at a LINK instruction, A6 has not been
  614.         go til (ΔA7)^        #   set up but ΔA7 probably contains the right value
  615.     else                    # if a LINK has already taken place,
  616.         go til (ΔA6+4)^        #   the return address is at ΔA6+4
  617.     end
  618. end
  619.  
  620. proc GoTil
  621.     CheckNullOrRunningTarget
  622.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  623.     if typeof(__sourceBreak__) = 'PString' then
  624.         alert concat('Cannot determine break address: ', __sourceBreak__)
  625.     else
  626.         go til __sourceBreak__
  627.     end
  628. end
  629.  
  630. proc InWhatStatement
  631.     CheckNullOrRunningTarget
  632.     if not addrToSource(ΔPC, SourceInFront) then
  633.         alert "Cannot find source for PC."
  634.     end
  635. end
  636.  
  637. proc ShowWhere
  638.     define __loc__
  639.     CheckNullTarget
  640.     __loc__ := sourceToAddr(ActiveWindow, 1)
  641.     if typeof(__loc__) = 'PString' then
  642.         alert concat('Cannot determine address from source: ', __loc__)
  643.     else
  644.         alert concat('At ', where(__loc__))
  645.     end
  646. end
  647.  
  648. proc __CheckNullSelection__(__theSelection__)
  649.     if length(__theSelection__) = 0 then
  650.         __Fail__("Selection is zero-length.")
  651.     end
  652. end
  653.  
  654. proc ShowSource(__theSelection__)
  655.     CheckNullTarget
  656.     __CheckNullSelection__(__theSelection__)
  657.     define __theFunc__ := eval(__theSelection__, '???')
  658.     if typeof(__theFunc__) = 'PString' then
  659.         if __theFunc__ = '???' then
  660.             alert concat('"', __theSelection__, '" is not a function or procedure name which is known at this point.')
  661.         else
  662.             alert concat('"', __theSelection__, '" is not a function or procedure name.')
  663.         end
  664.         abort
  665.     end
  666.     if typeof(__theFunc__) <> 'CodeModule' then
  667.         alert concat('"', __theSelection__, '" is not a function or procedure.')
  668.     elseif not addrToSource(__theFunc__, 1) then
  669.         alert concat('The source for "', __theSelection__, '" could not be found.')
  670.     end
  671. end
  672.  
  673. proc ShowValue(__theSelection__)
  674.     CheckNullOrRunningTarget
  675.     __CheckNullSelection__(__theSelection__)
  676.     open __gValueWindow__
  677.     redirect append __gValueWindow__
  678.     CheckValidLocalVars
  679.     PrettyPrintValue(__theSelection__)
  680.     redirect pop
  681. end
  682.     
  683. proc ShowValueInHex(__theSelection__)
  684.     CheckNullOrRunningTarget
  685.     __CheckNullSelection__(__theSelection__)
  686.     redirect append __gValueWindow__
  687.     CheckValidLocalVars
  688.     PrettyPrintValueInHex(__theSelection__)
  689.     redirect pop
  690.     open __gValueWindow__
  691. end
  692.  
  693. proc __CheckPointer__(__thePointer__)
  694.     define __ErrorMessage__
  695.     define __EvaledPointer__ := CheckedEval(__thePointer__, 'Undefined/Out of scope: ')
  696.     define __TypeofPointer__ := typeof(__EvaledPointer__)
  697.     if sizeof(__EvaledPointer__) <> 4 THEN
  698.         # Not a pointer object
  699.         __Fail__(concat(__thePointer__, " is not a pointer."))
  700.     end
  701.     if __TypeofPointer__ = '^Void' THEN
  702.         __Fail__(concat('Can not dereference (void*) ', __thePointer__))
  703.     end
  704.     if __EvaledPointer__ = 0 then
  705.         __ErrorMessage__ := concat('Cannot dereference NULL ', __thePointer__)
  706.         __Fail__(__ErrorMessage__)
  707.     end    
  708. end
  709.  
  710. proc ShowDereferencedValue(__theSelection__)
  711.     CheckNullOrRunningTarget
  712.     __CheckNullSelection__(__theSelection__)
  713.     __theSelection__ := QualifiedVariableName(__theSelection__)
  714.     __CheckPointer__(__theSelection__)
  715.     ShowValue(concat(__theSelection__, '^'))
  716. end
  717.  
  718. proc ShowDereferencedValueInHex(__theSelection__)
  719.     CheckNullOrRunningTarget
  720.     __CheckNullSelection__(__theSelection__)
  721.     __theSelection__ := QualifiedVariableName(__theSelection__)
  722.     __CheckPointer__(__theSelection__)
  723.     ShowValueInHex(concat(__theSelection__, '^'))
  724. end
  725.  
  726. proc AddWatchVar(__theSelection__)
  727.     CheckNullOrRunningTarget
  728.     __CheckNullSelection__(__theSelection__)
  729.     define __EvaledExpr__
  730.     if __NumWatchVars__ > (__MaxWatchVars__ - 1) then
  731.         alert "Cannot add more watch variables"
  732.     else
  733.         __theSelection__ := QualifiedVariableName(__theSelection__)
  734.         __EvaledExpr__ := eval(__theSelection__, '???')
  735.         if typeof(__EvaledExpr__) = 'PString' then
  736.             if copy(__EvaledExpr__, 1, 21) = '### eval syntax error' then
  737.                 alert concat('Cannot add watch variable.  Expression syntax error: ', __theSelection__)
  738.                 return
  739.             elseif __EvaledExpr__ = '???' then
  740.                 if not confirm(concat(__theSelection__, ' not defined at this time.  Still add as watch variable?')) then
  741.                     return
  742.                 end
  743.             end
  744.         end
  745.         __NumWatchVars__ := __NumWatchVars__ + 1
  746.         __WatchVar__[__NumWatchVars__] := __theSelection__
  747.         # Now refresh the display window
  748.         DisplayWatchVars
  749.     end
  750. end
  751.  
  752.  
  753. proc DeleteWatchVar(__theSelection__)
  754.     CheckNullTarget
  755.     __CheckNullSelection__(__theSelection__)
  756.     define __i__, __found__ := 0
  757.     __theSelection__ := QualifiedVariableName(__theSelection__)
  758.     for __i__ := 1 to __NumWatchVars__ do
  759.         if __found__ then
  760.             __WatchVar__[__i__-1] := __WatchVar__[__i__]
  761.         elseif __theSelection__ = __WatchVar__[__i__] then
  762.             __found__ := 1
  763.         end
  764.     end
  765.     if __found__ then
  766.         __WatchVar__[__NumWatchVars__] := 0
  767.         __NumWatchVars__ := __NumWatchVars__ - 1
  768.         # Now refresh the display window
  769.         DisplayWatchVars
  770.     else
  771.         alert concat('Cannot find watch variable "', __theSelection__, '" to delete')
  772.     end
  773. end
  774.  
  775. proc DeleteAllWatchVars
  776.     __NumWatchVars__ := 0
  777.     save concat(__ScratchDir__, "Variable Watch")
  778.     close concat(__ScratchDir__, "Variable Watch")
  779. end
  780.  
  781.  
  782. proc SADEHelp(__theSelection__)
  783.     define __HelpWindowName__ := concat(__ScratchDir__, "SADE_Info")
  784.     redirect __HelpWindowName__
  785.     printf "#   Select a word and then choose the SADE Help menu item.\n"
  786.     printf "#       try:  BuiltIns   Commands   Expressions  Patterns\n"
  787.     printf "#          :  Shortcuts  Variables  Basetypes    <commandName>\n\n"
  788.     #
  789.     if __theSelection__ = '' then
  790.         __theSelection__ := "Commands"
  791.     end
  792.     help expr(__theSelection__)
  793.     redirect pop
  794.     open __HelpWindowName__
  795.     define __dummy__
  796.     __dummy__ := selection(__HelpWindowName__, 0, 0)
  797. end
  798.  
  799.  
  800. #
  801. #
  802. # Killing or untargeting the target
  803. # Killing a target means to terminate it.  Untargeting it, however, simply means for
  804. # SADE to stop treating it as a target.  The semantics of untargeting are as follows:
  805. # if the target is running, it is left running.  If it is suspended at a breakpoint,
  806. # it is restarted.  If it is suspended due to a "hard" exception (e.g. a bus error),
  807. # it is killed.
  808. # Care is required in killing MPW tools.  Since in debugging a tool SADE's target is
  809. # actually the MPW shell, the kill command will kill the shell as well as the tool.
  810. # To avoid this, the KillTool proc below will kill a suspended tool without killing
  811. # the shell.  (KillTool won't kill a running tool.)  The KillTarget proc checks the
  812. # type of the target and executes either Kill or KillTool as appropriate.
  813. #
  814.  
  815. proc UnTarget
  816.     Target ''
  817.     __ClearBreakTable__
  818. end
  819.  
  820. proc KillTool
  821.     ΔPC := @µSYSRECOVER                # set the pc to the shell's error recovery routine
  822.     go
  823. end
  824.  
  825. proc KillTarget
  826.     if TargetIsMPWTool then
  827.         KillTool
  828.     else
  829.         kill
  830.     end
  831.     __ClearBreakTable__
  832.     __NumWatchVars__ := 0
  833. end
  834.  
  835.  
  836. #
  837. #
  838. # SADE menu initialization
  839. # Sets up SourceCmds and Variables menus, and adds Kill, Quit, and Help items
  840. # to the File menu.
  841. #
  842. #
  843.  
  844. addmenu 'File' 'Stop Before Constructor'                'ToggleStopBeforeStatic'
  845. addMenu 'File' 'Kill'                                    'KillTarget'
  846. addMenu 'File' '(-'                                        ''
  847.  
  848. # The default quit menu saves all dirty files before quitting.
  849. # Use the commented-out form if you'd rather be prompted than save automatically.
  850.  
  851. #addMenu 'File' 'Quit /Q'                                'quit'
  852. addMenu 'File' 'Quit /Q'                                'Save All;Quit'
  853.  
  854. addMenu 'Find' '(-'                                        ''
  855. addMenu 'Find' 'SADE Help/1'                             'SADEHelp(selection(ActiveWindow))'
  856.  
  857. addmenu 'SourceCmds' 'Break /B'                           'SetSourceBreak'
  858. addmenu 'SourceCmds' 'Break if…/∫'                        'SetSourceBreakIf'
  859. addmenu 'SourceCmds' 'Unbreak /U'                         'UnSetSourceBreak'
  860. addmenu 'SourceCmds' 'Unbreak All'                        '__UnbreakAll__'
  861. addmenu 'SourceCmds' '(-'                 ''
  862. addmenu 'SourceCmds' 'Step /L'                            'StepMenu'
  863. addmenu 'SourceCmds' 'Step Into /¬'                       'StepIntoMenu'        # '¬' is Opt-l
  864. addmenu 'SourceCmds' 'Step Out'                           'StepOut'
  865. addmenu 'SourceCmds' '(-'                 ''
  866. addmenu 'SourceCmds' 'Go /P'              'go'
  867. addmenu 'SourceCmds' 'Go Til /π'                         'GoTil'
  868. addmenu 'SourceCmds' '(-'                 ''
  869. addMenu 'SourceCmds' 'In What Statement? /I'            'InWhatStatement'
  870. addMenu 'SourceCmds' 'Statement Selected Is?'            'ShowWhere'
  871. addMenu 'SourceCmds' 'Show Selected Routine'            'ShowSource(selection(ActiveWindow))'
  872. addmenu 'SourceCmds' '(-'                 ''
  873. addmenu 'SourceCmds' 'Break if No Source'                'ToggleBreakifNoSource'
  874. addmenu 'SourceCmds' '!Source [vs. Asm] Debugging'        'ToggleSourceDbg'     # '' is control-r (a checkmark)
  875.  
  876. addmenu 'Variables'  'Show Value /√'                    'ShowValue(selection(ActiveWindow))'    # '√' is Opt-v
  877. addmenu 'Variables'  'Show Dereferenced Value /◊'        'ShowDereferencedValue(selection(ActiveWindow))'    # '◊' is Opt-shift-v
  878. addmenu 'Variables'  'Show Value in Hex'                'ShowValueInHex(selection(ActiveWindow))'
  879. addmenu 'Variables'  'Show Dereferenced Value in Hex'    'ShowDereferencedValueInHex(selection(ActiveWindow))'
  880. addmenu 'Variables'  '(-'                                ''
  881. addmenu 'Variables'  'Add Watch Variable'                'AddWatchVar(selection(ActiveWindow))'
  882. addmenu 'Variables'  'Delete Watch Variable'            'DeleteWatchVar(selection(ActiveWindow))'
  883. addmenu 'Variables'  'Delete All Watch Variables'        'DeleteAllWatchVars'
  884. addmenu 'Variables'  '(-'                                 ''
  885. addmenu 'Variables'  'Show Registers'                    'DisplayRegs'
  886. addmenu 'Variables'  'Live Register Window'                'ToggleWantRegisterWindow'
  887. addmenu 'Variables'  '(-'                 ''
  888. addmenu 'Variables'  'Show Stack'                        'DisplayStack'
  889. addmenu 'Variables'  'Live Stack Window'                'ToggleWantStackWindow'
  890.  
  891. #
  892. # Execute SADEUserStartup, where you can add to and modify the stuff supplied here.
  893. #
  894. # NOTE: The order in which SADE executes startup files is:  1. SadeStartup,
  895. # 2. SadeUserStartup, 3... Any SADE text file beginning with 'SadeUserStartup•',
  896. # in alphabetical order.  So if you want to override behavior defined in ANY other
  897. # script, be sure to define it in a script named something like 'SadeUserStartup•zzz'
  898. # which will be executed last.
  899. #
  900. execute ':SadeUserStartup'
  901.